#define SIMDE_TEST_ARM_NEON_INSN sha512

#include "test-neon.h"
#include "../../../simde/arm/neon/sha512.h"

static int
test_simde_vsha512hq_u64(SIMDE_MUNIT_TEST_ARGS) {
#if 1
  static const struct {
    uint64_t a[2];
    uint64_t b[2];
    uint64_t c[2];
    uint64_t r[2];
  } test_vec[] = {
    { {  UINT64_C( 4629218227708468224),  UINT64_C(12963963671126077440) },
      {  UINT64_C(12738748040677040128),  UINT64_C(11604793527862233088) },
      {  UINT64_C( 3175886359269796864),  UINT64_C(13729099243296088064) },
      {  UINT64_C(12129950801822637916),  UINT64_C( 4630221109811505045) } },
    { {  UINT64_C(12604932576983371776),  UINT64_C( 5222746509864651776) },
      {  UINT64_C( 3852752736150620160),  UINT64_C(18169232336839219200) },
      {  UINT64_C( 9708284858478970880),  UINT64_C(17812059722933958656) },
      {  UINT64_C( 9987884733109673041),  UINT64_C(14752174139020842854) } },
    { {  UINT64_C( 2859089985376329728),  UINT64_C( 6101630599793389568) },
      {  UINT64_C( 7010299481540315136),  UINT64_C(15735349109795481600) },
      {  UINT64_C(12252251885868201984),  UINT64_C(16477413551415246848) },
      {  UINT64_C(  162717127181638371),  UINT64_C(  612503903721911249) } },
    { {  UINT64_C(11024340864455858176),  UINT64_C( 9941575404751796224) },
      {  UINT64_C( 8254457170873521152),  UINT64_C(10838598048677357568) },
      {  UINT64_C( 2301888484161304576),  UINT64_C(12090059226833160192) },
      {  UINT64_C(15808783984405101280),  UINT64_C( 4787709777391384890) } },
    { {  UINT64_C(16667599763112534016),  UINT64_C( 1057474285385585792) },
      {  UINT64_C(17129454140930336768),  UINT64_C(10934458050134009856) },
      {  UINT64_C(14878180324063338496),  UINT64_C( 1449457267631441408) },
      {  UINT64_C(13969765458368780398),  UINT64_C(14569388191382577102) } },
    { {  UINT64_C(  375148869898363264),  UINT64_C(15682445102315982848) },
      {  UINT64_C( 3117125070717052416),  UINT64_C( 9688919790262634496) },
      {  UINT64_C( 2813015552213989376),  UINT64_C( 7407542507689576448) },
      {  UINT64_C( 2919832005068647087),  UINT64_C(10596913566963883754) } },
    { {  UINT64_C(16405913430250760192),  UINT64_C(16019214806218158080) },
      {  UINT64_C( 8161169376611441664),  UINT64_C( 9103999108554536960) },
      {  UINT64_C( 8365633854640427008),  UINT64_C(13779629045738129408) },
      {  UINT64_C(13829022853209456764),  UINT64_C( 5447022870655265776) } },
    { {  UINT64_C(14303733657765541888),  UINT64_C( 8535273352841077760) },
      {  UINT64_C(10543354550203822080),  UINT64_C(10000577295759722496) },
      {  UINT64_C(11632366153933049856),  UINT64_C(15986792746968436736) },
      {  UINT64_C(14889091621027400172),  UINT64_C(18113920993821757032) } },
  };

  for (size_t i = 0 ; i < (sizeof(test_vec) / sizeof(test_vec[0])) ; i++) {
    simde_uint64x2_t a = simde_vld1q_u64(test_vec[i].a);
    simde_uint64x2_t b = simde_vld1q_u64(test_vec[i].b);
    simde_uint64x2_t c = simde_vld1q_u64(test_vec[i].c);
    simde_uint64x2_t r = simde_vsha512hq_u64(a, b, c);

    simde_test_arm_neon_assert_equal_u64x2(r, simde_vld1q_u64(test_vec[i].r));
  }

  return 0;

#else
  fputc('\n', stdout);
  for (int i = 0 ; i < 8 ; i++) {
    simde_uint64x2_t a = simde_test_arm_neon_random_u64x2();
    simde_uint64x2_t b = simde_test_arm_neon_random_u64x2();
    simde_uint64x2_t c = simde_test_arm_neon_random_u64x2();
    simde_uint64x2_t r = simde_vsha512hq_u64(a, b, c);

    simde_test_arm_neon_write_u64x2(2, a, SIMDE_TEST_VEC_POS_FIRST);
    simde_test_arm_neon_write_u64x2(2, b, SIMDE_TEST_VEC_POS_MIDDLE);
    simde_test_arm_neon_write_u64x2(2, c, SIMDE_TEST_VEC_POS_MIDDLE);
    simde_test_arm_neon_write_u64x2(2, r, SIMDE_TEST_VEC_POS_LAST);
  }
  return 1;
#endif
}

static int
test_simde_vsha512h2q_u64(SIMDE_MUNIT_TEST_ARGS) {
#if 1
  static const struct {
    uint64_t a[2];
    uint64_t b[2];
    uint64_t c[2];
    uint64_t r[2];
  } test_vec[] = {
    { {  UINT64_C(12851197626935529472),  UINT64_C(14124313819546007552) },
      {  UINT64_C(18355891854836740096),  UINT64_C( 9399838822377455616) },
      {  UINT64_C( 6009040859660153856),  UINT64_C( 7590246084135089152) },
      {  UINT64_C(11927264895006306731),  UINT64_C( 3247568491421886536) } },
    { {  UINT64_C(18336681668416854016),  UINT64_C(17331481844296902656) },
      {  UINT64_C( 7577630546984204288),  UINT64_C(16486472415973859328) },
      {  UINT64_C(14117414804339574784),  UINT64_C( 8880984689449663488) },
      {  UINT64_C( 3491191940113343175),  UINT64_C( 5515922572363325767) } },
    { {  UINT64_C( 4034437781994614784),  UINT64_C( 1890604266473533952) },
      {  UINT64_C( 6436931536364713984),  UINT64_C(13916003456185950208) },
      {  UINT64_C(14527630781761361920),  UINT64_C( 7215944217676346368) },
      {  UINT64_C(  889706241481720863),  UINT64_C( 6458228891581289554) } },
    { {  UINT64_C( 8926603622325986304),  UINT64_C( 2258111520724332544) },
      {  UINT64_C( 9065405086820889600),  UINT64_C(15675496744226465792) },
      {  UINT64_C(12103821184687032320),  UINT64_C( 2649807695462505472) },
      {  UINT64_C(16969042801225907503),  UINT64_C(16319888631816734540) } },
    { {  UINT64_C( 4731766721616798720),  UINT64_C(16880401209896353792) },
      {  UINT64_C(10569192447815921664),  UINT64_C(14852624489117595648) },
      {  UINT64_C(  399572706690869504),  UINT64_C( 3920002610776208896) },
      {  UINT64_C( 5915827737079008329),  UINT64_C(16203079633205090133) } },
    { {  UINT64_C(13859397821753020416),  UINT64_C( 5481680527888486400) },
      {  UINT64_C( 7710982346417406976),  UINT64_C( 7656559858584227840) },
      {  UINT64_C( 4914253734855530496),  UINT64_C( 2958644895145309184) },
      {  UINT64_C(10926886508873771908),  UINT64_C( 9728610516250839538) } },
    { {  UINT64_C( 8245041662259017728),  UINT64_C( 3133372043942539264) },
      {  UINT64_C( 5681846580889421824),  UINT64_C( 1334709058729996032) },
      {  UINT64_C(17126369016278259712),  UINT64_C( 6290502933719902208) },
      {  UINT64_C(15373503074427719706),  UINT64_C( 1659928139966740811) } },
    { {  UINT64_C(16415608870894964736),  UINT64_C( 8612169767380567040) },
      {  UINT64_C(16860612379805505536),  UINT64_C( 2070081918734190080) },
      {  UINT64_C( 5880807934234644480),  UINT64_C( 8192054319505615872) },
      {  UINT64_C(14938555820509327110),  UINT64_C(16135372770631177157) } },
  };

  for (size_t i = 0 ; i < (sizeof(test_vec) / sizeof(test_vec[0])) ; i++) {
    simde_uint64x2_t a = simde_vld1q_u64(test_vec[i].a);
    simde_uint64x2_t b = simde_vld1q_u64(test_vec[i].b);
    simde_uint64x2_t c = simde_vld1q_u64(test_vec[i].c);
    simde_uint64x2_t r = simde_vsha512h2q_u64(a, b, c);

    simde_test_arm_neon_assert_equal_u64x2(r, simde_vld1q_u64(test_vec[i].r));
  }

  return 0;

#else
  fputc('\n', stdout);
  for (int i = 0 ; i < 8 ; i++) {
    simde_uint64x2_t a = simde_test_arm_neon_random_u64x2();
    simde_uint64x2_t b = simde_test_arm_neon_random_u64x2();
    simde_uint64x2_t c = simde_test_arm_neon_random_u64x2();
    simde_uint64x2_t r = simde_vsha512h2q_u64(a, b, c);

    simde_test_arm_neon_write_u64x2(2, a, SIMDE_TEST_VEC_POS_FIRST);
    simde_test_arm_neon_write_u64x2(2, b, SIMDE_TEST_VEC_POS_MIDDLE);
    simde_test_arm_neon_write_u64x2(2, c, SIMDE_TEST_VEC_POS_MIDDLE);
    simde_test_arm_neon_write_u64x2(2, r, SIMDE_TEST_VEC_POS_LAST);
  }
  return 1;
#endif
}

static int
test_simde_vsha512su0q_u64(SIMDE_MUNIT_TEST_ARGS) {
#if 1
  static const struct {
    uint64_t a[2];
    uint64_t b[2];
    uint64_t r[2];
  } test_vec[] = {
    { {  UINT64_C( 4601031596841025024),  UINT64_C( 4654670052286818304) },
      {  UINT64_C(17483440813270777856),  UINT64_C( 6692779630772066304) },
      {  UINT64_C( 6946830027034207928),  UINT64_C(13321626111095275200) } },
    { {  UINT64_C( 8864530735650216960),  UINT64_C( 9649108713047107584) },
      {  UINT64_C( 2099256840155623424),  UINT64_C( 5716955059415528448) },
      {  UINT64_C(13726864929116724728),  UINT64_C(10709250607648786704) } },
    { {  UINT64_C( 1624047369457394944),  UINT64_C(16687169699519862784) },
      {  UINT64_C( 7741005656060785664),  UINT64_C(13201216653478989824) },
      {  UINT64_C( 9902477064204219944),  UINT64_C( 2062714403469278492) } },
    { {  UINT64_C( 5517000970059928576),  UINT64_C( 5811073805110560768) },
      {  UINT64_C( 2050505423238296320),  UINT64_C( 5332575035499483136) },
      {  UINT64_C( 8445296574240148440),  UINT64_C( 6828588823682228757) } },
    { {  UINT64_C( 8171999998956306432),  UINT64_C( 4083844277605185024) },
      {  UINT64_C( 2822187600868528128),  UINT64_C( 6168669839007337472) },
      {  UINT64_C(10198523701626463834),  UINT64_C( 5523950386222552688) } },
    { {  UINT64_C(  174762853128746112),  UINT64_C( 7910696297275397120) },
      {  UINT64_C( 6092089576970109952),  UINT64_C(10016397420016699392) },
      {  UINT64_C( 4089060255698245052),  UINT64_C(10988946284598438988) } },
    { {  UINT64_C( 1473007872437497088),  UINT64_C(13462274061131771904) },
      {  UINT64_C(  562799648029544576),  UINT64_C(13209145414241331200) },
      {  UINT64_C( 8149235709212512272),  UINT64_C( 4522604886198482033) } },
    { {  UINT64_C(14334734463220060160),  UINT64_C( 8421390715225748480) },
      {  UINT64_C( 4609425874196063744),  UINT64_C(17216900159273388032) },
      {  UINT64_C(  135454660325448924),  UINT64_C(10708062898192734890) } },
  };

  for (size_t i = 0 ; i < (sizeof(test_vec) / sizeof(test_vec[0])) ; i++) {
    simde_uint64x2_t a = simde_vld1q_u64(test_vec[i].a);
    simde_uint64x2_t b = simde_vld1q_u64(test_vec[i].b);
    simde_uint64x2_t r = simde_vsha512su0q_u64(a, b);

    simde_test_arm_neon_assert_equal_u64x2(r, simde_vld1q_u64(test_vec[i].r));
  }

  return 0;

#else
  fputc('\n', stdout);
  for (int i = 0 ; i < 8 ; i++) {
    simde_uint64x2_t a = simde_test_arm_neon_random_u64x2();
    simde_uint64x2_t b = simde_test_arm_neon_random_u64x2();
    simde_uint64x2_t r = simde_vsha512su0q_u64(a, b);

    simde_test_arm_neon_write_u64x2(2, a, SIMDE_TEST_VEC_POS_FIRST);
    simde_test_arm_neon_write_u64x2(2, b, SIMDE_TEST_VEC_POS_MIDDLE);
    simde_test_arm_neon_write_u64x2(2, r, SIMDE_TEST_VEC_POS_LAST);
  }
  return 1;
#endif
}

static int
test_simde_vsha512su1q_u64(SIMDE_MUNIT_TEST_ARGS) {
#if 1
  static const struct {
    uint64_t a[2];
    uint64_t b[2];
    uint64_t c[2];
    uint64_t r[2];
  } test_vec[] = {
    { {  UINT64_C( 6422233210691667968),  UINT64_C(17336331784991213568) },
      {  UINT64_C( 5111910551163907072),  UINT64_C( 9844465460326029312) },
      {  UINT64_C( 8570298257642457088),  UINT64_C(17485694959021240320) },
      {  UINT64_C( 4837741413934441732),  UINT64_C(16219594276616920750) } },
    { {  UINT64_C(14914818225674864640),  UINT64_C( 6404293397467455488) },
      {  UINT64_C( 5713758283606673408),  UINT64_C(17375144802653558784) },
      {  UINT64_C( 7706481337490279424),  UINT64_C(11271267826252281856) },
      {  UINT64_C( 7806677374028588664),  UINT64_C(16649809866611886083) } },
    { {  UINT64_C(11577274482172993536),  UINT64_C( 7590132217368291328) },
      {  UINT64_C(17486747677918736384),  UINT64_C(  947319326722582912) },
      {  UINT64_C(10831738453137215488),  UINT64_C( 5946646586545910784) },
      {  UINT64_C( 1701999641948010144),  UINT64_C(    1483728883210083) } },
    { {  UINT64_C( 7564447192640522240),  UINT64_C( 4715087384581673984) },
      {  UINT64_C(11037348937553446912),  UINT64_C( 5482424699884019712) },
      {  UINT64_C( 3047891151446764544),  UINT64_C( 5818633108179639296) },
      {  UINT64_C( 7874415882314726841),  UINT64_C(13243688791157296527) } },
    { {  UINT64_C( 5824137663402675200),  UINT64_C( 7885723337239161856) },
      {  UINT64_C(10603841566975875072),  UINT64_C(12577172642315057152) },
      {  UINT64_C( 9141858263831357440),  UINT64_C( 5496658799268696064) },
      {  UINT64_C( 2288360820535972519),  UINT64_C(14671122480778687515) } },
    { {  UINT64_C( 7739163393999130624),  UINT64_C( 4928476145888352256) },
      {  UINT64_C(14170378039124871168),  UINT64_C(13056805623766972416) },
      {  UINT64_C(13494599878725767168),  UINT64_C(12616084759446806528) },
      {  UINT64_C( 7338144423263237703),  UINT64_C(14395531788248046043) } },
    { {  UINT64_C( 4090843550304700928),  UINT64_C(  943772910256974208) },
      {  UINT64_C(13712176154574002176),  UINT64_C( 2829728468099620352) },
      {  UINT64_C(13960536899176337408),  UINT64_C( 3558312501678472192) },
      {  UINT64_C( 1019406612744535227),  UINT64_C(10371586688589124869) } },
    { {  UINT64_C(  182620672199997408),  UINT64_C( 6515587073751916544) },
      {  UINT64_C(17155745380901191680),  UINT64_C(14122100795215757312) },
      {  UINT64_C(14194165624435322880),  UINT64_C( 5943118735598111744) },
      {  UINT64_C(18057304952478182546),  UINT64_C(12805986210024573861) } },
  };

  for (size_t i = 0 ; i < (sizeof(test_vec) / sizeof(test_vec[0])) ; i++) {
    simde_uint64x2_t a = simde_vld1q_u64(test_vec[i].a);
    simde_uint64x2_t b = simde_vld1q_u64(test_vec[i].b);
    simde_uint64x2_t c = simde_vld1q_u64(test_vec[i].c);
    simde_uint64x2_t r = simde_vsha512su1q_u64(a, b, c);

    simde_test_arm_neon_assert_equal_u64x2(r, simde_vld1q_u64(test_vec[i].r));
  }

  return 0;

#else
  fputc('\n', stdout);
  for (int i = 0 ; i < 8 ; i++) {
    simde_uint64x2_t a = simde_test_arm_neon_random_u64x2();
    simde_uint64x2_t b = simde_test_arm_neon_random_u64x2();
    simde_uint64x2_t c = simde_test_arm_neon_random_u64x2();
    simde_uint64x2_t r = simde_vsha512su1q_u64(a, b, c);

    simde_test_arm_neon_write_u64x2(2, a, SIMDE_TEST_VEC_POS_FIRST);
    simde_test_arm_neon_write_u64x2(2, b, SIMDE_TEST_VEC_POS_MIDDLE);
    simde_test_arm_neon_write_u64x2(2, c, SIMDE_TEST_VEC_POS_MIDDLE);
    simde_test_arm_neon_write_u64x2(2, r, SIMDE_TEST_VEC_POS_LAST);
  }
  return 1;
#endif
}

SIMDE_TEST_FUNC_LIST_BEGIN
SIMDE_TEST_FUNC_LIST_ENTRY(vsha512hq_u64)
SIMDE_TEST_FUNC_LIST_ENTRY(vsha512h2q_u64)
SIMDE_TEST_FUNC_LIST_ENTRY(vsha512su0q_u64)
SIMDE_TEST_FUNC_LIST_ENTRY(vsha512su1q_u64)
SIMDE_TEST_FUNC_LIST_END

#include "test-neon-footer.h"
